#!/usr/bin/env python
# -*- coding:utf-8 -*-
import base64
import hmac
import urllib
from hashlib import sha256
import json
import datetime
#yum install python-requests -y or pip2 install requests
import requests
import ssl
import time
import logging
import sys

class qingyun:
   #签名前排序
  def setdictsort(self,adict,types):
    i=0
    if types=='key':
      i=0
    else:
      i=1
    return sorted(adict.items(),key=lambda item:item[i])

  #获取青云签名
  def getqingyunsignature(self,urlstr,secret_access_key):
    # 前面生成的被签名串
    
    string_to_sign = 'GET\n/iaas/\n'

    string_to_sign=string_to_sign+urlstr
    
    #print '最后的url参数：',string_to_sign

    #先sha256编码
    h = hmac.new(secret_access_key, digestmod=sha256)
    h.update(string_to_sign)
    #再base64编码，去除空格
    sign = base64.b64encode(h.digest()).strip()
    #再URL编码
    signature = urllib.quote_plus(sign)
    return signature


  #异常返回值说明,返回【kp-*】为自定义信息，其它为青云官网定义
  def getname(self,id):
    if(id=='kp-error-10000'): return '[this-服务ID不存在]'
    elif(id=='kp-error-10001'): return '[this-查询的后端服务ID和接口返回的服务ID不一致]'
    elif(id=='kp-error-10002'): return '[this-参数有误，请输入正确的disabled]'
    elif(id=='up'): return '[青云-后端服务状态可用]'
    elif(id=='down'): return '[青云-后端服务状态不可用]'
    elif(id=='abnormal'): return '[青云-后端服务状态异常]'
    elif(id=='0'): return '[青云-接口调用成功]'
    else: return ''
      
  #查询负载均衡器中的服务状态
  def DescribeLoadBalancerBackends(self,this,access_key_id,secret_access_key,loadbalancer,loadbalancer_listener,loadbalancer_backends,zone):
    action="DescribeLoadBalancerBackends"
    signature_method="HmacSHA256"
    dictinfo={
        "action":action,
        "zone":zone,
        "time_stamp":datetime.datetime.utcnow().strftime("%Y-%m-%dT%H:%M:%SZ"),
        "access_key_id":access_key_id,
        "version":1,
        "signature_method":signature_method,
        "signature_version":1,
        "loadbalancer":loadbalancer,
        "loadbalancer_listener":loadbalancer_listener,
        "loadbalancer_backends":loadbalancer_backends,
        "verbose":1
      }


    apijson=this.getqingyunapi(dictinfo)

    if (apijson.get('total_count')==0):
      return 'kp-error-10000'

    lbs=apijson['loadbalancer_backend_set'][0]
    #print '返回的服务为:',lbs,type(lbs) 
    lbs_status=lbs['status']
    lbs_lbid=lbs['loadbalancer_backend_id']    
    
    if(loadbalancer_backends==lbs_lbid):
      #unicode转str
      s_str = lbs_status.encode('unicode-escape').decode('string_escape')
      loginfo='workcode:【'+workcode+'】,【---获取服务状态---】,返回值:【'+s_str+'】,释义:【'+this.getname(s_str)+'】,负载均衡器ID:【'+loadbalancer+'】,监听器ID:【'+loadbalancer_listener+'】,后端服务ID:【'+loadbalancer_backends +'】'
      this.console_out(loginfo,'info') 
      return s_str
    else:
      errorinfo='kp-error-10001'
      loginfo='workcode:【'+workcode+'】,【---获取服务状态---】,返回值:【'+errorinfo+'】,释义:【'+this.getname(errorinfo)+'】,负载均衡器ID:【'+loadbalancer+'】,监听器ID:【'+loadbalancer_listener+'】,后端服务ID:【'+loadbalancer_backends +'】'
      this.console_out(loginfo,'info') 
      return errorinfo 

  #根据参数返回接口结果
  def getqingyunapi(self,dictinfo):
    strinfo=this.setdictsort(dictinfo,'key')
    #print '排序后：',strinfo

    urlstr=urllib.urlencode(strinfo)
    #print 'url转化2：',urlstr

    signature=this.getqingyunsignature(urlstr,secret_access_key)
    #print '最后签名：',signature

    strsql="https://api.qingcloud.com/iaas/?"+urlstr+"&signature="+signature
    #print strsql

    #调用青云接口获取对应的值
    retapistr=requests.get(strsql).content
    #print("retapistr值为:",retapistr,type(retapistr))

    apijson=json.loads(retapistr)
    #print "apijson返回值:",apijson,type(apijson),apijson['total_count']
    return apijson
    
  #更改负载均衡器中的服务状态,disabled:1表示禁用，0表示启用
  def ModifyLoadBalancerBackendAttributes(self,this,access_key_id,secret_access_key,loadbalancer_backend,zone,disabled):
    action="ModifyLoadBalancerBackendAttributes"
    signature_method="HmacSHA256"
    dictinfo={
        "action":action,
        "zone":zone,
        "time_stamp":datetime.datetime.utcnow().strftime("%Y-%m-%dT%H:%M:%SZ"),
        "access_key_id":access_key_id,
        "version":1,
        "signature_method":signature_method,
        "signature_version":1,
        "loadbalancer_backend":loadbalancer_backend,
        "verbose":1,
        "disabled":disabled
      }

    apijson=this.getqingyunapi(dictinfo)

    #int to str
    s_str = str(apijson['ret_code'])
    loginfo=''
    if(disabled==0):
      loginfo='workcode:【'+workcode+'】,【---更新后端服务状态为运行---】,返回值:【'+s_str+'】,释义:【'+this.getname(s_str)+'】,负载均衡器ID:【'+loadbalancer+'】,监听器ID:【'+loadbalancer_listener+'】,后端服务ID:【'+loadbalancer_backends +'】'
    else:
      loginfo='workcode:【'+workcode+'】,【---更新后端服务状态为停止---】,返回值:【'+s_str+'】,释义:【'+this.getname(s_str)+'】,负载均衡器ID:【'+loadbalancer+'】,监听器ID:【'+loadbalancer_listener+'】,后端服务ID:【'+loadbalancer_backends +'】'
    this.console_out(loginfo,'info') 
    return s_str

  #执行负载均衡器更新配置后的下发，不下发之前的命令不起效
  def UpdateLoadBalancers(self,this,access_key_id,secret_access_key,loadbalancer,zone):
    action="UpdateLoadBalancers"
    signature_method="HmacSHA256"
    dictinfo={
        "action":action,
        "zone":zone,
        "time_stamp":datetime.datetime.utcnow().strftime("%Y-%m-%dT%H:%M:%SZ"),
        "access_key_id":access_key_id,
        "version":1,
        "signature_method":signature_method,
        "signature_version":1,
        "loadbalancers.1":loadbalancer
      }

    apijson=this.getqingyunapi(dictinfo)

    lbs_status=apijson['ret_code']
    s_str = str(lbs_status)
    loginfo='workcode:【'+workcode+'】,【---执行下发命令---】,返回值:【'+s_str+'】,释义:【'+this.getname(s_str)+'】负载均衡器ID:【'+loadbalancer+'】,监听器ID:【'+loadbalancer_listener+'】,后端服务ID:【'+loadbalancer_backends +'】'
    this.console_out(loginfo,'info') 

    return lbs_status   

  #写入日志
  def console_out(self,message,loglevel):
    filenames=sys.path[0]+'/logs/qingyun.'+str(datetime.datetime.now().strftime("%Y%m%d"))+'.log'
    #  这里进行判断，如果logger.handlers列表为空，则添加，否则，直接去写日志
  

    logging.basicConfig(
        level=logging.INFO,  # 定义输出到文件的log级别，大于此级别的都被输出
        format='%(asctime)s  %(filename)s : %(levelname)s  %(message)s',  # 定义输出log的格式
        datefmt='%Y-%m-%d %A %H:%M:%S',  # 时间
        filename=filenames,  # log文件名
        filemode='a')  # 写入模式“w”或“a”
    # Define a Handler and set a format which output to console
    console = logging.StreamHandler()  # 定义console handler
    console.setLevel(logging.INFO)  # 定义该handler级别
    formatter = logging.Formatter('%(asctime)s  %(filename)s : %(levelname)s  %(message)s')  # 定义该handler格式
    console.setFormatter(formatter)
    logging.getLogger().addHandler(console)  # 实例化添加handler

  
    if(loglevel=='info'):
      logging.info(message)
    elif(loglevel=='error'):
      logging.error(message)
    else:
      logging.info(message)

    #输出完需要清理
    logging.getLogger().removeHandler(console)

  #读取json文件
  # def loadFont(self):
  #   f = open(sys.path[0]+"/conf/nodeconf.json", encoding='utf-8')  #设置以utf-8解码模式读取文件，encoding参数必须设置，否则默认以gbk模式读取文件，当文件中包含中文时，会报错
  #   setting = json.load(f)
  #   family = setting['BaseSettings']['size']   #注意多重结构的读取语法
  #   size = setting['fontSize']   
  #   return family
 


if __name__ == '__main__':

  #本次任务的编号
  workcode=datetime.datetime.now().strftime("%Y%m%d%H%M%S.%f")

  this=qingyun()
  #青云key_id
  access_key_id="NVZXMHPSPKAKKYOTADQZ"
  #青云access_key
  secret_access_key='38SBm8EVk6N138NG9sriqp7h2VOEqXpuKnx5Dyag'
  #负载均衡器ID
  loadbalancer=""
  #监听器ID
  loadbalancer_listener=""
  #后端服务ID
  loadbalancer_backends=""
  zone=""
  isset=""
  #更新后端服务状态,disabled:1表示禁用，0表示启用
  disabled=0
  iserror=0
  this.console_out('','info')

  try:
    projecttype = sys.argv[1]
    projectname = sys.argv[2]
    isset = sys.argv[3]
    
  except  Exception:
    loginfo='workcode:【'+workcode+'】,【---输入参数有误error---】'
    this.console_out(loginfo,'info')
  else:
    loginfo='workcode:【'+workcode+'】,【---本次输入的配置参数如下---】,projecttype:【'+projecttype+'】,projectname:【'+projectname+'】,disabled:【'+isset +'】'
    this.console_out(loginfo,'info')

  #node项目配置
  
  if projecttype=="nodeconf" or projecttype=="pythonconf" or projecttype=="javaconf":
    f = open(sys.path[0]+"/conf/"+projecttype+".json")
    setting = json.load(f,encoding="utf-8")
    listconf=setting[projecttype]
    i=0
    while (i<len(listconf)):
      confprojectname= listconf[i]["projectname"]
      if(projectname==confprojectname):
        #负载均衡器ID
        loadbalancer=listconf[i]["loadbalancer"].encode('unicode-escape').decode('string_escape')
        #监听器ID
        loadbalancer_listener=listconf[i]["loadbalancer_listener"].encode('unicode-escape').decode('string_escape')
        #后端服务ID
        loadbalancer_backends=listconf[i]["loadbalancer_backends"].encode('unicode-escape').decode('string_escape')
        #区域
        zone=listconf[i]["zone"].encode('unicode-escape').decode('string_escape')
        break
      i=i+1
  else:
    iserror=1

  

  if(isset=="down"):
    disabled=1   
  elif(isset=="up"):
    disabled=0
  else:
    disabled=2
    iserror=1

  
  loginfo='workcode:【'+workcode+'】,【---本次任务参数如下---】,loadbalancer:【'+loadbalancer +'】,loadbalancer_listener:【'+loadbalancer_listener+'】,loadbalancer_backends:【'+loadbalancer_backends+'】,zone:【'+zone+'】,disabled:【' +str(disabled) +'】'
  this.console_out(loginfo,'info')

  if(iserror==1):
    this.console_out('workcode:【'+workcode+'】,【参数有误，请检查！】','error')
    #终止任务
    sys.exit(0)
    #return 'kp-error-10002'

  #调试
  #sys.exit(0)
  #更新前获取指定服务状态
  lbs_status=this.DescribeLoadBalancerBackends(this,access_key_id,secret_access_key,loadbalancer,loadbalancer_listener,loadbalancer_backends,zone)
  
  if(lbs_status==isset):
    this.console_out('workcode:【'+workcode+'】,【本次更新的目的和当前状态一致，不用更新sueccess！】','info')
    sys.exit(0)
    #return '0'
 
  #更新服务状态
  lbs_status=this.ModifyLoadBalancerBackendAttributes(this,access_key_id,secret_access_key,loadbalancer_backends,zone,disabled)
  #执行下发命令，不下发的话更新不起作用
  lbs_status=this.UpdateLoadBalancers(this,access_key_id,secret_access_key,loadbalancer,zone)
   
  this.console_out('workcode:【'+workcode+'】【命令执行中...，等待5秒后查询状态】','info')
  while(True): 
    #命令执行中，等待...
    time.sleep(5)
    #获取指定服务最新负载均衡的状态
    lbs_status=this.DescribeLoadBalancerBackends(this,access_key_id,secret_access_key,loadbalancer,loadbalancer_listener,loadbalancer_backends,zone)
    if(lbs_status==isset):
      this.console_out('workcode:【'+workcode+'】【本次更新负载均衡器后台服务sueccess】','info') 
      break
      #如果需要的话返回结果
    else:
      this.console_out('workcode:【'+workcode+'】【状态未更新warning，等待5秒后查询状态】','info') 
      
 
  
  


   
  

  
  
